package com.jse;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;

public class Urls {

	public static String query(Map<String,String> params,Charset charset) {
        if (params == null || params.isEmpty()) {
            return null;
        }
        StringBuilder query = new StringBuilder();
        Set<Entry<String, String>> entries = params.entrySet();
        boolean hasParam = false;
        for (Entry<String, String> entry : entries) {
            String name = entry.getKey();
            String value = entry.getValue();
            // 忽略参数名或参数值为空的参数
            if (!Strings.isEmpty(name)&&!Strings.isEmpty(value)) {
                if (hasParam) {
                    query.append("&");
                } else {
                    hasParam = true;
                }
                query.append(name).append("=").append(URLEncoder.encode(value, charset));
            }
        }
        return query.toString();
    }
	
	public static final String CLASSPATH_URL_PREFIX = "classpath:";
	public static final String URL_PROTOCOL_FILE = "file";

	public static final String encode(String str){
		if(Strings.isEmpty(str)){return "";}
		try{
			return URLEncoder.encode(str,"UTF-8");
		}catch (Exception e){
			throw new RuntimeException(e);
		}
	}
	public static final String decode(String str){
		if(Strings.isEmpty(str)){return "";}
		try{
			return URLDecoder.decode(str,"UTF-8");
		}catch(Exception e){
			throw new RuntimeException("url 解码错误",e);
		}
	}
	/**
	 * 获取去除后缀的链接
	 * 
	 * @param url 获取的链接
	 * @return
	 */
	public static String removeSuffix(String url) {
		if (url.lastIndexOf(".") == -1) {
			return url;
		} else {
			return url.substring(0, url.lastIndexOf("."));
		}
	}
	
	public final static List<String> domainSuffixs = Arrays.asList(new String(
			"com|org|net|gov|edu|co|tv|mobi|info|asia|xxx|onion|cn|com.cn|edu.cn|gov.cn|net.cn|org.cn|jp|kr|tw|com.hk|hk|com.hk|org.hk|se|com.se|org.se")
			.split("\\|"));
	private static Pattern IP_PATTERN = Pattern.compile("(\\d{1,3}\\.){3}(\\d{1,3})");

	/**
	 * 获取url的顶级域名
	 * 
	 * @param url
	 * @return
	 */
	public static String domain(URL url) {
		String host = url.getHost();
		if (host.endsWith(".")) {
			host = host.substring(0, host.length() - 1);
		}
		if (IP_PATTERN.matcher(host).matches()) {
			return host;
		}
		int index = 0;
		String candidate = host;
		for (; index >= 0;) {
			index = candidate.indexOf('.');
			String subCandidate = candidate.substring(index + 1);
			if (domainSuffixs.contains(subCandidate)) {
				return candidate;
			}
			candidate = subCandidate;
		}
		return candidate;
	}

	/**
	 * 获取url的顶级域名
	 * 
	 * @param url
	 * @return
	 * @throws MalformedURLException
	 */
	public static String domain(String url) {
		try {
			return domain(new URL(url));
		} catch (MalformedURLException e) {
			return "";
		}
	}

	/**
	 * 判断两个url顶级域名是否相等
	 * 
	 * @param url1
	 * @param url2
	 * @return
	 */
	public static boolean isSameDomain(URL url1, URL url2) {
		return domain(url1).equalsIgnoreCase(domain(url2));
	}

	/**
	 * 判断两个url顶级域名是否相等
	 * 
	 * @param url1
	 * @param url2
	 * @return
	 * @throws MalformedURLException
	 */
	public static boolean isSameDomain(String url1, String url2) {
		try {
			return isSameDomain(new URL(url1), new URL(url2));
		} catch (MalformedURLException e) {
			return false;
		}
	}

	public static String suffix(String url) {
		if (url.lastIndexOf(".") == -1) {
			return "";
		} else {
			return url.substring(url.lastIndexOf(".") + 1, url.length());
		}
	}
	public static String suffix(String url,String def) {
		if (url.lastIndexOf(".") == -1) {
			return def;
		} else {
			return url.substring(url.lastIndexOf(".") + 1, url.length());
		}
	}
	
	/**
	 * String转换成URI
	 *
	 * @param url 路径
	 * @return URI
	 * @throws URISyntaxException 转换不了URI抛出异常
	 */
	public static URI uri(String url) {
		try {
			return new URI(url.replace(" ", "%20"));
		} catch (URISyntaxException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * URL转换成URI
	 *
	 * @param url 路径
	 * @return URI
	 * @throws URISyntaxException 转换不了URI抛出异常
	 */
	public static URI uri(URL url) throws URISyntaxException {
		return new URI(url.toString().replace(" ", "%20"));
	}
	
	public static File file(String resourceLocation) throws FileNotFoundException {
		if (resourceLocation.startsWith("/")) {
			String path = resourceLocation;
			String description = "class path resource [" + path + "]";
			ClassLoader cl = Jse.clazz.getClassLoader();
			URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
			if (url == null) {
				throw new FileNotFoundException(
						description + " cannot be resolved to absolute file path because it does not exist");
			}
			return file(url, description);
		}else if (resourceLocation.startsWith(CLASSPATH_URL_PREFIX)) {
			String path = resourceLocation.substring(CLASSPATH_URL_PREFIX.length());
			String description = "class path resource [" + path + "]";
			ClassLoader cl = Jse.clazz.getClassLoader();
			URL url = (cl != null ? cl.getResource(path) : ClassLoader.getSystemResource(path));
			if (url == null) {
				throw new FileNotFoundException(
						description + " cannot be resolved to absolute file path because it does not exist");
			}
			return file(url, description);
		}
		try {
			// try URL
			return file(new URL(resourceLocation));
		} catch (MalformedURLException ex) {
			// no URL -> treat as file path
			return new File(resourceLocation);
		}
	}
	
	public static File file(URL resourceUrl) throws FileNotFoundException {
		return file(resourceUrl, "URL");
	}

	public static File file(URL resourceUrl, String description) throws FileNotFoundException {
		if (!URL_PROTOCOL_FILE.equals(resourceUrl.getProtocol())) {
			throw new FileNotFoundException(description + " cannot be resolved to absolute file path "
					+ "because it does not reside in the file system: " + resourceUrl);
		}
		try {
			return new File(uri(resourceUrl).getSchemeSpecificPart());
		} catch (URISyntaxException ex) {
			// Fallback for URLs that are not valid URIs (should hardly ever happen).
			return new File(resourceUrl.getFile());
		}
	}
	/**
	 * 路径拼接
	 *
	 * @param parent 父路径
	 * @param child  子路径
	 * @return path
	 */
	public static String concat(String parent, String child) {
		StringBuilder sb = new StringBuilder(parent);
		if (parent.endsWith("/") && child.startsWith("/")) {
			sb.deleteCharAt(sb.length() - 1);
		}
		if (!parent.endsWith("/") && !child.startsWith("/")) {
			sb.append("/");
		}
		sb.append(child);
		if (sb.indexOf("/") != 0) {
			sb.insert(0, "/");
		}
		if (sb.length() > 1 && sb.lastIndexOf("/") == sb.length() - 1) {
			sb.deleteCharAt(sb.length() - 1);
		}
		return sb.toString();
	}
	
	/**
	   * 获取不含通配符的根路径
	   *
	   * @param location 路径
	   * @return 根路径
	   */
	  public static String getRootDir(String location) {
	    int prefixEnd = location.indexOf(":") + 1;
	    int rootDirEnd = location.length();
	    while (rootDirEnd > prefixEnd && Strings.isPattern(location.substring(prefixEnd, rootDirEnd))) {
	      rootDirEnd = location.lastIndexOf("/", rootDirEnd - 2) + 1;
	    }
	    if (rootDirEnd == 0) {
	      rootDirEnd = prefixEnd;
	    }
	    return location.substring(0, rootDirEnd);
	  }
	  
	  /**
		 * 去除路径起始的/
		 *
		 * @param path 路径
		 * @return 处理后的路径
		 */
		public static String cutRootPath(String path) {
			String usePath = path;
			if (usePath.charAt(0)=='/') {
				usePath = usePath.substring(1);
			}
			return usePath;
		}
		
		/**
		 * 获取jar文件
		 *
		 * @param jarFileUrl jar文件路径
		 * @return jar文件
		 * @throws IOException io异常
		 */
		public static JarFile getJarFile(String jarFileUrl) throws IOException {
			if (jarFileUrl.startsWith("file:")) {
				return new JarFile(uri(jarFileUrl).getSchemeSpecificPart());
			} else {
				return new JarFile(jarFileUrl);
			}
		}

		/**
		 * 获取jar信息
		 *
		 * @param url url
		 * @return jarFileInfo
		 * @throws IOException io异常
		 */
		public static JarFile jarFile(URL url) throws IOException {
			URLConnection con = url.openConnection();
			JarFile jarFile;
			String jarFileUrl;
			if (con instanceof JarURLConnection) {
				JarURLConnection jarCon = (JarURLConnection) con;
				jarFile = jarCon.getJarFile();
			} else {
				String urlFile = url.getFile();
				int separatorIndex = urlFile.indexOf("*/");
				if (separatorIndex == -1) {
					separatorIndex = urlFile.indexOf("!/");
				}
				if (separatorIndex != -1) {
					jarFileUrl = urlFile.substring(0, separatorIndex);
					jarFile = getJarFile(jarFileUrl);
				} else {
					jarFile = new JarFile(urlFile);
				}
			}
			return jarFile;
		}

		public static String jarFileUrl(URL url) throws IOException {
			URLConnection con = url.openConnection();
			String jarFileUrl;
			if (con instanceof JarURLConnection) {
				JarURLConnection jarCon = (JarURLConnection) con;
				jarFileUrl = jarCon.getJarFileURL().toExternalForm();
			} else {
				String urlFile = url.getFile();
				int separatorIndex = urlFile.indexOf("*/");
				if (separatorIndex == -1) {
					separatorIndex = urlFile.indexOf("!/");
				}
				if (separatorIndex != -1) {
					jarFileUrl = urlFile.substring(0, separatorIndex);
				} else {
					jarFileUrl = urlFile;
				}
			}
			return jarFileUrl;
		}

		public static String jarFilePath(URL url) throws IOException {
			URLConnection con = url.openConnection();
			String rootEntryPath;
			if (con instanceof JarURLConnection) {
				JarURLConnection jarCon = (JarURLConnection) con;
				JarEntry jarEntry = jarCon.getJarEntry();
				rootEntryPath = (jarEntry != null ? jarEntry.getName() : "");
			} else {
				String urlFile = url.getFile();
				int separatorLength = "*/".length();
				int separatorIndex = urlFile.indexOf("*/");
				if (separatorIndex == -1) {
					separatorIndex = urlFile.indexOf("!/");
					separatorLength = "!/".length();
				}
				if (separatorIndex != -1) {
					rootEntryPath = urlFile.substring(separatorIndex + separatorLength);
				} else {
					rootEntryPath = "";
				}
			}
			return rootEntryPath;
		}
}
